/*
 * This file is part of JGAP.
 *
 * JGAP offers a dual license model containing the LGPL as well as the MPL.
 *
 * For licensing information please see the file license.txt included with JGAP
 * or have a look at the top of class org.jgap.Chromosome which representatively
 * includes the JGAP license policy applicable for any file delivered with JGAP.
 */
package tp4_ia_ag;

import org.jgap.*;
import org.jgap.impl.*;
import org.jgap.impl.salesman.*;

/**
 * Explains how to use JGAP extensions, needed to solve the task group,
 * known as the <i>Problem of the travelling salesman</i>. The extensions are
 * defined in {@link org.jgap.impl.salesman org.jgap.impl.salesman}
 *
 * <font size=-1><p>
 * The traveling salesman problem is the following: given a finite number of
 * 'cities' along with the cost of travel between each pair of them, find the
 * cheapest way of visiting all the cities and returning to your starting point.
 * </p></font>
 *
 * Also see
 *  <ul>
 *   <li>J. Grefenstette, R. Gopal, R. Rosmaita, and D. Gucht.
 *     <i>Genetic algorithms for the traveling salesman problem</i>.
 *     In Proceedings of the Second International Conference on Genetice
 *     Algorithms. Lawrence Eribaum Associates, Mahwah, NJ, 1985.
 *   </li>
 *   <li>
 *    <a href="http://ecsl.cs.unr.edu/docs/techreports/gong/node3.html">
 *      Sushil J. Louis & Gong Li</a> (very clear explanatory material)
 *   </li>
 *   <li>
 *     <a href="http://www.tsp.gatech.edu www.tsp.gatech.edu">
 *        <i>Travelling salesman</i> web site</a>
 *   </li>
 * </ul>
 *
 * This simple test and example shows how to use the Salesman class.
 * The distance between the cities is assumed to be equal
 * to the difference of the assigned numbers. So, the
 * optimal solution is obviously 1 2 3 4 ... n or reverse,
 * but the system does not know this. To get the useful application, you
 * need to override at least the distance function. Also, it is recommended
 * to define a new type of gene, corresponding the data about your "city".
 * For example, it can contain the city X and Y co-ordinates, used by
 * the distance function.
 *
 * @author Audrius Meskauskas
 * @since 2.0
 */
public class TravellingSalesmanPto1
    extends Salesman {
  /** String containing the CVS revision. Read out via reflection!*/
  private static final String CVS_REVISION = "$Revision: 1.14 $";

  /** The number of cities to visit*/
  public static final int CITIES = 9;

  public static final int[][] CITYARRAY = new int[][] { {2, 4}, {7, 5}, {7, 11},
      {8, 1}, {1, 6}, {5, 9}, {0, 11}
  };
  /**
   * Create an array of the given number of integer genes. The first gene is
   * always 0, this is the city where the salesman starts the journey.
   *
   * @param a_initial_data ignored
   * @return Chromosome
   *
   * @author Audrius Meskauskas
   * @since 2.0
   */
  public IChromosome createSampleChromosome(Object a_initial_data) {
    try {
      Gene[] genes = new Gene[CITIES];

      genes[0] = new IntegerGene(getConfiguration(), 0, 8);
      genes[1] = new IntegerGene(getConfiguration(), 0, 8);
      genes[2] = new IntegerGene(getConfiguration(), 0, 8);
      genes[3] = new IntegerGene(getConfiguration(), 0, 8);
      genes[4] = new IntegerGene(getConfiguration(), 0, 8);
      genes[5] = new IntegerGene(getConfiguration(), 0, 8);
      genes[6] = new IntegerGene(getConfiguration(), 0, 8);
      genes[7] = new IntegerGene(getConfiguration(), 0, 8);
      genes[8] = new IntegerGene(getConfiguration(), 0, 8);

      genes[0].setAllele(new Integer(0));
      genes[1].setAllele(new Integer(8));
      genes[2].setAllele(new Integer(7));
      genes[3].setAllele(new Integer(3));
      genes[4].setAllele(new Integer(4));
      genes[5].setAllele(new Integer(6));
      genes[6].setAllele(new Integer(5));
      genes[7].setAllele(new Integer(1));
      genes[8].setAllele(new Integer(2));

      
//      for (int i = 0; i < genes.length; i++) {
//        genes[i] = new IntegerGene(getConfiguration(), 0, CITIES - 1);
//        genes[i].setAllele(new Integer(i));
//      }
      IChromosome sample = new Chromosome(getConfiguration(), genes);
      return sample;
    }
    catch (InvalidConfigurationException iex) {
      throw new IllegalStateException(iex.getMessage());
    }
  }

  /**
   * Distance is equal to the difference between city numbers, except the
   * distance between the last and first cities that is equal to 1. In this
   * way, we ensure that the optimal solution is 0 1 2 3 .. n - easy to check.
   *
   * @param a_from first gene, representing a city
   * @param a_to second gene, representing a city
   * @return the distance between two cities represented as genes

   * @author Audrius Meskauskas
   * @since 2.0
   */
  public double distance(Gene a_from, Gene a_to) {
    IntegerGene geneA = (IntegerGene) a_from;
    IntegerGene geneB = (IntegerGene) a_to;
    int a = geneA.intValue();
    int b = geneB.intValue();
//    int x1 = CITYARRAY[a][0];
//    int y1 = CITYARRAY[a][1];
//    int x2 = CITYARRAY[b][0];
//    int y2 = CITYARRAY[b][1];

    if(CityMatrixs.CITY_TIME[a][b]==0){
        return 10000;
        //throw new IllegalStateException("ERRRRRROR");//iex.getMessage());//return 10000;
    }
    else{
        double agr=0;
        if(a==0) agr = (CityMatrixs.CLIENTS_PER_CITY[a]*20)/60;
        return ((CityMatrixs.CITY_TIME[a][b]+CityMatrixs.CLIENTS_PER_CITY[b]*20)/60);
    }
  }
  public static double getKm(int aa, int bb) {
      int a=aa;
      int b=bb;

    if(CityMatrixs.CITY_DISTANCE[a][b]==0){
        return 10000;
        //throw new IllegalStateException("ERRRRRROR");//iex.getMessage());//return 10000;
    }
    else{
        return CityMatrixs.CITY_DISTANCE[a][b];
    }
  }
  public static double getTimeGen(int aa, int bb) {
      int a=aa;
      int b=bb;

    if(CityMatrixs.CITY_TIME[a][b]==0){
        return 10000;
        //throw new IllegalStateException("ERRRRRROR");//iex.getMessage());//return 10000;
    }
    else{
          double agr=0;
          if(a==0) agr = (CityMatrixs.CLIENTS_PER_CITY[a]*20)/60;
        return ((CityMatrixs.CITY_TIME[a][b]+CityMatrixs.CLIENTS_PER_CITY[b]*20)/60)+agr;
    }
  }

 public IChromosome getPunto1(){
     try {
      TravellingSalesmanPto1 t;
      double b=10001;
      int iteraciones=0;
      IChromosome superOptimo=null;
      int maxCity=0;
      double maxHours=0;
      while(iteraciones<51){//b>10000 && iteraciones<101){
          Configuration.reset();
          t = new TravellingSalesmanPto1();
          iteraciones++;
          t.setPopulationSize(500);//5000);
          t.setMaxEvolution(10);
          //t.setStartOffset(32);
          IChromosome optimal = t.findOptimalPath(null);
          System.out.println("Solution: ");
          System.out.println(optimal);
          b=Integer.MAX_VALUE / 2 - optimal.getFitnessValue();
          System.out.println("Score " +
                             (Integer.MAX_VALUE / 2 - optimal.getFitnessValue()));

          if(getCitiesNumber(optimal)[0]>=maxCity){
//              if(getCitiesNumber(optimal)[0]==maxCity && getCitiesNumber(optimal)[1]>maxHours){
//                  maxCity=(int)getCitiesNumber(optimal)[0];
//                  maxHours=getCitiesNumber(optimal)[1];
//                  superOptimo=optimal;
//              }
//              else{
                  maxCity=(int)getCitiesNumber(optimal)[0];
                  maxHours=getCitiesNumber(optimal)[1];
                  superOptimo=optimal;
              //}
          }
      }
      System.out.println("Iteraciones: "+iteraciones);

      ciuMax=maxCity;
      horasUtil=maxHours;
      System.out.println("\n Super solucion, ciudade: "+maxCity+" - horas:"+maxHours);
      System.out.println(superOptimo);
      System.out.println("Score " +
                             (Integer.MAX_VALUE / 2 - superOptimo.getFitnessValue()));
      return superOptimo;
    }
    catch (Exception ex) {
        System.out.println("Eror excepcion"+ex);
        return null;
    }
 }

 private double horasUtil;
 public double getHorasUtil(){
    return horasUtil;
 }
 private int ciuMax;
 
  public static void main(String[] args) {
    try {
      TravellingSalesmanPto1 t;
      double b=10001;
      int iteraciones=0;
      IChromosome superOptimo=null;
      int maxCity=0;
      double maxHours=0;
      while(iteraciones<100){//b>10000 && iteraciones<101){
          Configuration.reset();
          t = new TravellingSalesmanPto1();
          iteraciones++;
          t.setPopulationSize(500);//5000);
          t.setMaxEvolution(10);
          //t.setStartOffset(32);
          IChromosome optimal = t.findOptimalPath(null);
          System.out.println("Solution: ");
          System.out.println(optimal);
          b=Integer.MAX_VALUE / 2 - optimal.getFitnessValue();
          System.out.println("Score " +
                             (Integer.MAX_VALUE / 2 - optimal.getFitnessValue()));

          if(getCitiesNumber(optimal)[0]>=maxCity){
//              if(getCitiesNumber(optimal)[0]==maxCity && getCitiesNumber(optimal)[1]>maxHours){
//                  maxCity=(int)getCitiesNumber(optimal)[0];
//                  maxHours=getCitiesNumber(optimal)[1];
//                  superOptimo=optimal;
//              }
//              else{
                  maxCity=(int)getCitiesNumber(optimal)[0];
                  maxHours=getCitiesNumber(optimal)[1];
                  superOptimo=optimal;
              //}
          }
      }
      System.out.println("Iteraciones: "+iteraciones);

      System.out.println("\n Super solucion, ciudade: "+maxCity+" - horas:"+maxHours);
      System.out.println(superOptimo);
      System.out.println("Score " +
                             (Integer.MAX_VALUE / 2 - superOptimo.getFitnessValue()));
    }
    catch (Exception ex) {
        System.out.println("Eror excepcion"+ex);
    }
  }
  public static double getMaxKm(IChromosome iChro, int index){
      double km=0;
      double aux=0;     
      for(int i=0;i<index;i++){
          km=km+getKm((Integer)iChro.getGene(i).getAllele(), (
                  Integer)iChro.getGene(i+1).getAllele());
      }
      return km;
  }
    public static double getMaxTime(IChromosome iChro, int index){
      double time=0;
      double aux=0;
      for(int i=0;i<index;i++){
          time=time+getTimeGen((Integer)iChro.getGene(i).getAllele(), (
                  Integer)iChro.getGene(i+1).getAllele());
      }
      return time;
  }
  public static double[] getCitiesNumber(IChromosome iChro){
      double hours=0;
      int cit=0;
      double aux=0;
      int i=0;
      Integer c1= (Integer)iChro.getGene(0).getAllele();
      Integer c2 = (Integer) iChro.getGene(1).getAllele();
      Integer c3 = (Integer) iChro.getGene(2).getAllele();
      Integer c4= (Integer)iChro.getGene(3).getAllele();
      Integer c5 = (Integer) iChro.getGene(4).getAllele();
      Integer c6 = (Integer) iChro.getGene(5).getAllele();
      Integer c7= (Integer)iChro.getGene(6).getAllele();
      Integer c8 = (Integer) iChro.getGene(7).getAllele();
      Integer c9 = (Integer) iChro.getGene(8).getAllele();
      while(hours<=12 && cit<8){
          aux=hours;
          hours=hours+getTimeGen((Integer)iChro.getGene(i).getAllele(), (
                  Integer)iChro.getGene(i+1).getAllele());
          i++;
          cit++;
      }

      double[] toReturn=new double[]{cit-1,aux};
      return toReturn;
  }

    /**
     * @return the ciuMax
     */
    public int getCiuMax() {
        return ciuMax;
    }

    /**
     * @param ciuMax the ciuMax to set
     */
    public void setCiuMax(int ciuMax) {
        this.ciuMax = ciuMax;
    }
}
